/**
 * @Author       : Hejh(3010733382@qq.com)
 * @Version      : V1.0
 * @Date         : 2024-01-18 11:21:49
 * @Description  : 定时任务接口验证器
 */

const Joi = require('joi')
const cronParse = require('cron-parser')
const R = require('@/models/Response')
const { ERROR_USER_CODE, ERROR_SYSTEM_CODE } = require('@/constants/errorCode')
const { IS_INTEGER, IS_UNSAFE_INTEGER } = require('@/constants/joiSchema')
const { dumpCheck } = require('@/utils/dumpCheck')

const scheduleTaskSchema = {
  scheduleTaskIds: Joi.array().items(IS_UNSAFE_INTEGER),
  scheduleTaskId: IS_UNSAFE_INTEGER,
  page: IS_INTEGER.min(1).default(1),
  pageSize: IS_INTEGER.min(1).default(999),
  name: Joi.string().min(1).max(50),
  desc: Joi.string().max(255).allow(''),
  url: Joi.string().max(255),
  // type: IS_INTEGER.valid(0, 1),
  time: Joi.string(),
  isActive: IS_INTEGER.valid(0, 1)
}

const urlValidate = {
  // 允许的内部方法
  methodsArr: [
    'system.backup',
    'system.cleanFile',
    'system.exportLog',
    'system.secrtyUpdate'
  ]
}

/**
 * @description 计划任务列表查询的参数验证
 * @param {*} ctx
 * @param {*} next
 * @returns
 */
module.exports.listScheduleTaskValidate = async (ctx, next) => {
  const schema = Joi.object({
    page: scheduleTaskSchema.page,
    pageSize: scheduleTaskSchema.pageSize
  }).validate(ctx.query)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }
  ctx.query = schema.value
  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 创建和更新计划任务时的验证
 * @param {*} ctx koa上下文
 * @param {*} scheduleTaskId 计划任务ID
 * @param {*} name 计划任务名称
 * @param {array<string>} type 计划任务类型
 * @param {*} url 计划任务方法或者请求地址
 * @param {*} time 计划任务执行时间
 */
const addAndUpdCheck = async (ctx, scheduleTaskId, name, type, url, time) => {
  // 验证计划任务ID的合法性
  if (scheduleTaskId !== null) {
    const b4 = await dumpCheck.checkScheduleTaskIds([scheduleTaskId])
    if (!b4) {
      ctx.body = R.error(ERROR_USER_CODE.SCHEDULE_TASK_ID_ERROR)
      return false
    }
  }

  // 验证计划任务名称的合法性
  if (name !== null && !scheduleTaskId) {
    const b3 = await dumpCheck.checkScheduleTaskName(name)
    if (!b3) {
      ctx.body = R.error(ERROR_USER_CODE.SCHEDULE_TASK_NAME_ERROR)
      return false
    }
  }

  // 根据type判断是接口路由还是内置方法
  // if (type !== null) {
  //   if (+type === 0) {
  //     // 接口路由
  //     if (!urlValidate.urlArr.includes(url)) {
  //       ctx.body = R.error(ERROR_USER_CODE.SCHEDULE_TASK_URL_ERROR)
  //       return false
  //     }
  //   } else if (+type === 1) {
  //     // 内置方法
  //     if (!urlValidate.methodsArr.includes(url)) {
  //       ctx.body = R.error(ERROR_USER_CODE.SCHEDULE_TASK_METHOD_ERROR)
  //       return false
  //     }
  //   }
  // }

  if (!urlValidate.methodsArr.includes(url)) {
    ctx.body = R.error(ERROR_USER_CODE.SCHEDULE_TASK_METHOD_ERROR)
    return false
  }

  // 验证time是否满足cron表达式
  if (time !== null) {
    try {
      cronParse.parseExpression(time)
    } catch (error) {
      ctx.body = R.error(ERROR_USER_CODE.SCHEDULE_TASK_TIME_ERROR)
      return false
    }
  }

  return true
}

/**
 * @description 创建计划任务时的参数验证
 * @param {*} ctx
 * @param {*} next
 * @returns
 */
module.exports.createScheduleTaskValidate = async (ctx, next) => {
  const schema = Joi.object({
    name: scheduleTaskSchema.name.required(),
    desc: scheduleTaskSchema.desc.required(),
    // type: scheduleTaskSchema.type.required(),
    url: scheduleTaskSchema.url.required(),
    isActive: scheduleTaskSchema.isActive.required(),
    time: scheduleTaskSchema.time.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { name, type, url, time } = ctx.request.body
  // 验证name是否重复，url是否正确，time是否满足cron表达式
  const b = await addAndUpdCheck(ctx, null, name, type, url, time)
  if (!b) {
    return
  }

  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 更新计划任务时的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.updateScheduleTaskValidate = async (ctx, next) => {
  const schema = Joi.object({
    scheduleTaskId: scheduleTaskSchema.scheduleTaskId.required(),
    name: scheduleTaskSchema.name.required(),
    desc: scheduleTaskSchema.desc.required(),
    // type: scheduleTaskSchema.type.required(),
    url: scheduleTaskSchema.url.required(),
    isActive: scheduleTaskSchema.isActive.required(),
    time: scheduleTaskSchema.time.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { scheduleTaskId, name, type, url, time } = ctx.request.body
  // 验证id是否正确，name是否重复，url是否正确，time是否满足cron表达式
  const b = await addAndUpdCheck(ctx, scheduleTaskId, name, type, url, time)
  if (!b) {
    return
  }
  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 批量删除计划任务接口的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.delScheduleTasksValidate = async (ctx, next) => {
  const schema = Joi.object({
    scheduleTaskIds: scheduleTaskSchema.scheduleTaskIds.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    console.log(schema.error)
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { scheduleTaskIds } = ctx.request.body

  // 验证计划任务ID数组的合法性
  const b4 = await dumpCheck.checkScheduleTaskIds(scheduleTaskIds, [
    { field: 'system', value: 0 }
  ])
  if (!b4) {
    ctx.body = R.error(ERROR_USER_CODE.SCHEDULE_TASK_ID_ERROR)
    return
  }

  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 计划任务排序接口的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.sortScheduleTasksValidate = async (ctx, next) => {
  const schema = Joi.object({
    scheduleTaskIds: scheduleTaskSchema.scheduleTaskIds.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { scheduleTaskIds } = ctx.request.body

  // 验证计划任务ID数组的合法性
  const b4 = await dumpCheck.checkScheduleTaskIds(scheduleTaskIds)
  if (!b4) {
    ctx.body = R.error(ERROR_USER_CODE.SCHEDULE_TASK_ID_ERROR)
    return
  }

  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 计划任务运行接口的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.runScheduleTaskValidate = async (ctx, next) => {
  const schema = Joi.object({
    scheduleTaskId: scheduleTaskSchema.scheduleTaskId.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { scheduleTaskId } = ctx.request.body

  // 验证计划任务ID数组的合法性
  const b4 = await dumpCheck.checkScheduleTaskIds([scheduleTaskId])
  if (!b4) {
    ctx.body = R.error(ERROR_USER_CODE.SCHEDULE_TASK_ID_ERROR)
    return
  }

  await next()
}
